fscanf в C/C++: считывание из файла
Привет! В этой статье мы поговорим о функции fscanf
. Эта функция очень похожа на scanf
с тем отличием, что она считывает значения не из стандартного ввода, а из файла. Начнем мы с обзора этой функци и на примерах, а потом посмотрим на спецификаторы формата, которые эта функция поддерживает (они не отличаются от scanf
, поэтому знание этой функции будет большим плюсом). В конце есть упражнения для закрепления материала.
Как считать значения из файла с помощью fscanf
Для считывания значений из файла можно воспользоваться функцией fscanf
. Э та функция объявлена в заголовочном файле <stdio.h>
. В C++ вы можете подключить <cstdio>
. Выглядит эта функция вот так:
int fscanf ( FILE * stream, const char * format, ... );
- Первым аргументом нужно передать указатель на файл, из которого нужно производить считывание.
- Вторым аргументом нужно передать строку формата, которая определяет как нужно читать файл.
- Далее нужно передать столько аргументов, сколько
fscanf
будет ожидать в зависимости от строки формата. - Функция возвращает количество значений, которые удалось считать из файла. Если все прошло без ошибок, то это значение должно быть равно количеству аргументов после строки формата.
Давайте посмотрим на несколько примеров использования этой функции:
#include <stdio.h>
int main() {
FILE * f = fopen("input.txt", "r");
int x;
int n = fscanf(f, "x: %d", &x);
fclose(f);
printf("x = %d, n = %d", x, n);
return 0;
}
input.txt:
x: 4
Вывод программы:
x = 4, n = 1
В программе выше мы считали переменную типа int
из файла, используя спецификатор формата %d
(подробнее о спецификаторах ниже). После считывания, мы вывели x
и количество считанных аргументов.
Давайте теперь попробуем считать что-то посложнее:
#include <stdio.h>
int main() {
FILE* f = fopen("input.txt", "r");
unsigned int x;
char s[100];
float pi;
int n = fscanf(f, "hex: %x, s = %s\nfloat <- %f", &x, s, &pi);
fclose(f);
printf("x = %d, s = %s, pi = %f, n = %d", x, s, pi, n);
return 0;
}
input.txt:
hex: 0xABC, s = fscanf
float <- 3.14
Вывод программы:
x = 2748, s = fscanf, pi = 3.140000, n = 3
Как вы можете видеть, fscanf
справился со сложным форматом. Давайте теперь “испортим” содержимое файла input.txt, чтобы fscanf
смог считать только первые два значения:
hex: 0xABC, s = fscanf
UNKNOWN <- 3.14
Тут мы поменяли начало второй строки. Давайте теперь запустим программу выше и посмотрим на ее вывод:
x = 2748, s = fscanf, pi = 0.000000, n = 2
Тут все ожидаемо:
fscanf
смог прочитать первые два значения, поскольку тут ничего не поменялось.- Но при считывании второй строки файла,
fscanf
уже встречает неожиданный символU
. На этом считывание заканчивается. - В итоге мы видим, что только два значение было считано (
n
равно двум).pi
остался со значением по умолчанию (в данном случае нулем).
Что будет выведено на экран?
#include <stdio.h>
int main() {
FILE* f = fopen("data.txt", "r");
char word[50];
double number;
int n = fscanf(f, "%s = %lf", word, &number);
fclose(f);
printf("word = %s, number = %lf, n = %d", word, number, n);
return 0;
}
data.txt:
result = 42.58
Давайте теперь посмотрим на все возможные спецификаторы формата, которые можно использовать с функцией fscanf
.
Спецификаторы формата
Структура спецификатора в fscanf
немного отличается от спецификатора в fprintf
(в квадратных скобках опциональные модификаторы):
%[*][ширина][размер]тип
Как видите, обязательными являются только знак процента и тип; остальные можно не использовать. Сами спецификаторы никак не отличаются от спецификаторов функции scanf
(той, которая читает из стандартного ввода, а не из файла).
Тип
Тип | Описание | Пример | Файл |
---|---|---|---|
i | Считывает целое число в восьмеричной, десятеричной или шестнадцатеричной системе. |
|
|
d | Считывает целое число в десятеричной системе. |
|
|
u | Считывает целое положительное число в десятеричной системе. |
|
|
o | Считывает целое число в восьмеричной системе. |
|
|
x | Считывает целое число в шестнадцатеричной системе. |
|
|
f , e , g , a | Считывает вещественное число. |
|
|
c | Считывает символ. |
|
|
s | Считывает строку до первого пробельного символа. |
|
|
p | Считывает адрес в памяти. |
|
|
[<символы>] | Считывает строку до тех пор, пока не встретит символ, который отличается от символов, внутри квадратных скобок. |
|
|
[^<символы>] | Считывает строку до тех пор, пока не встретит символ, который совпадает с одним из символов, внутри квадратных скобок, после |
|
|
n | Ничего не считывает. Записывает количество считанных символов до этого момента. |
|
|
%% | Считывает знак процента. |
|
|
Игнорирование ввода
Мы можем указать звездочку после процента, чтобы не сохранять прочитанное значение:
FILE * f = fopen("input.txt", "r");
int x;
fscanf(f, "Пропустить: %*d, сохранить: %d", &x);
printf("Число: %d", x);
input.txt:
Пропустить: 123, сохранить: 456
Пример вывода:
Число: 456
Звездочку можно использовать с любым типом из таблицы выше, не только с числами.
Ширина
Мы можем указать максимальное количество символов, которое будет прочитано функцией fscanf
при считывании значения:
FILE * f = fopen("input.txt", "r");
char s[4]; // 3 символа + '\0'
fscanf(f, "%3s", s);
printf("Считали: %s", s);
input.txt:
C++11
Вывод:
Считали: C++
Как и звездочка, ширину можно указывать для любого типа.
Размер
По умолчанию fscanf
считывает значения типа int
, unsigned int
, float
и char
(зависит от типа спецификатора). Чтобы считать, например, значение в переменную типа long long int
, нам нужно явно указать размер:
#include <math.h>
#include <stdio.h>
int main() {
FILE * f = fopen("input.txt", "r");
long long int x;
printf("Число: ");
fscanf(f, "%lld", &x);
// ^ добавили ll для long long int
printf("Считали: %lld\n", x);
// ^ в printf тоже не забываем
return 0;
}
input.txt:
Число: 10000000000
Вывод:
Считали: 10000000000
Без указания размера вывод будет выглядеть примерно так:
Считали: 5705032704
Мы видим такой вывод, потому что десять миллиардов просто не влезают в тип int
, который fscanf
пытается считать без явного указания размера.
Вот таблица размеров, которые можно использовать:
Размер | Тип |
---|---|
hh |
|
h |
|
l |
|
ll |
|
j |
|
z |
|
t |
|
L |
|
Упражнения
- Считывание различных типов данных:
Напишите программу на C++, которая использует функциюfscanf
для считывания данных разных типов из файла. В файле должны быть следующие данные: целое число, вещественное число, строка. После считывания, программа должна выводить эти данные на экран. - Обработка ошибок считывания:
Измените ваш файл с данными таким образом, чтобы одна из строк не соответствовала формату, который вы ожидаете. Затем модифицируйте вашу программу так, чтобы она корректно обрабатывала этот случай (например, выводила сообщение об ошибке). - Использование различных спецификаторов формата:
Напишите программу, которая демонстрирует использование разных спецификаторов формата с функциейfscanf
. Создайте файл с различными данными (например, целыми числами, вещественными числами, строками, шестнадцатеричными числами) и считайте их из файла, выводя результат на экран.
Если хотите всегда быть в курсе последних новостей в мире п рограммирования и IT, подписываетесь на мой Telegram-канал, где я делюсь свежими статьями, новостями и полезными советами. Буду рад видеть вас среди подписчиков!
Обсуждение